﻿using BaseicModuleExpression.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using BaseicModuleExpression.MappingExtend;
using System.Diagnostics;

namespace BaseicModuleExpression.Module
{
    public class ExpressionAdd
    {
        public void Run()
        {
            #region 练习拼接表达目录树
            {
                ////加法拼接
                //Expression<Func<int>> expression = () => 12 + 33;
                //ConstantExpression constantExpression = Expression.Constant(12, typeof(int));
                //ConstantExpression constantExpression1 = Expression.Constant(33, typeof(int));
                //BinaryExpression binaryExpression = Expression.Add(constantExpression, constantExpression1);
                //Expression<Func<int>> expression1 = Expression.Lambda<Func<int>>(binaryExpression, new ParameterExpression[0]);
                //Func<int> func = expression1.Compile();
                //var xx = func.Invoke();


                ////乘法拼接
                //Expression<Func<int, int, int>> expression = (m, n) => m * n + m + n + 2;
                //var m = Expression.Parameter(typeof(int), "m");
                //var n = Expression.Parameter(typeof(int), "n");
                //var constact = Expression.Constant(2);
                //BinaryExpression one = Expression.Multiply(m, n);
                //BinaryExpression two = Expression.Add(one, m);
                //BinaryExpression three = Expression.Add(two, n);
                //BinaryExpression thor = Expression.Add(three, constact);
                //Expression<Func<int, int, int>> expression1 = Expression.Lambda<Func<int, int, int>>(thor, new ParameterExpression[] { m, n });
                //int func = expression1.Compile().Invoke(2, 2);


                ////调用表达式目录树 
                ////Expression<Func<User, bool>> expression = x => x.Name.ToString().Equals("你好");
                //ParameterExpression parameterExpression = Expression.Parameter(typeof(User), "x");
                //PropertyInfo propertyInfo = typeof(User).GetProperty("Name");
                //MemberExpression memberExpression = Expression.Property(parameterExpression, propertyInfo);
                //MethodInfo methodInfo = typeof(string).GetMethod("ToString", new Type[] { });
                //MethodCallExpression methodCallExpression = Expression.Call(memberExpression, methodInfo);
                //MethodInfo methodInfo1 = typeof(string).GetMethod("Equals", new Type[] { typeof(string) });
                //ConstantExpression constantExpression = Expression.Constant("你好");
                //MethodCallExpression methodCallExpression1 = Expression.Call(methodCallExpression, methodInfo1, new Expression[] { constantExpression });
                //Expression<Func<User, bool>> expression = Expression.Lambda<Func<User, bool>>(methodCallExpression1, new ParameterExpression[] { parameterExpression });
                //bool bl = expression.Compile().Invoke(new User { Id = 1, Name = "你好" });

                //List<User> users = new List<User>();
                //users.Where(x => x.Id == 1);
                //var xx = users.AsQueryable();
                //var w = xx.Where(x => x.Id == 1);
            }
            #endregion

            #region 动态拼接查询条件
            {
                ////Expression<Func<User, bool>> expression = x => x.Name.Contains("xx") && x.Age > 0;
                //ConstantExpression constantExpression = Expression.Constant(1);
                //BinaryExpression binaryExpression = Expression.Equal(constantExpression, constantExpression);

                //ParameterExpression parameterExpression = Expression.Parameter(typeof(User), "x");
                //PropertyInfo propertyInfo = typeof(User).GetProperty("Name");
                //MemberExpression memberExpression = Expression.Property(parameterExpression, propertyInfo);
                //MethodInfo methodInfo = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
                //MethodCallExpression methodCallExpression = Expression.Call(memberExpression, methodInfo, Expression.Constant("xx", typeof(string)));

                //BinaryExpression binaryExpression1 = Expression.AndAlso(binaryExpression, methodCallExpression);

                //PropertyInfo propertyInfo1 = typeof(User).GetProperty("Age");
                //ConstantExpression constantExpression1 = Expression.Constant(0);
                //MemberExpression memberExpression1 = Expression.Property(parameterExpression, propertyInfo1);
                //BinaryExpression binaryExpression2 = Expression.GreaterThan(memberExpression1, constantExpression1);

                //BinaryExpression binaryExpression3 = Expression.AndAlso(binaryExpression1, binaryExpression2);

                //Expression<Func<User, bool>> expression = Expression.Lambda<Func<User, bool>>(binaryExpression3, new ParameterExpression[] { parameterExpression });
                //var bl = expression.Compile().Invoke(new User { Id = 1, Name = "xxxxx", Age = 5 });
            }
            #endregion

            #region 测试 转换dto赋值 性能 消耗时间
            {
                //People people = new People()
                //{
                //    Id = 11,
                //    Name = "Eleven",
                //    Age = 31
                //};
                ////PeopleCopy copy = (PeopleCopy)people;

                //PeopleCopy peopleCopy = new PeopleCopy()
                //{
                //    Id = people.Id,
                //    Name = people.Name,
                //    Age = people.Age
                //};
                ////假如程序中有很多这样的转换，为每个类型都这样硬编码？！
                //PeopleCopy peopleCopy1 = ReflectionMapper.Trans<People, PeopleCopy>(people);//1 反射
                //PeopleCopy peopleCopy2 = SerializeMapper.Trans<People, PeopleCopy>(people); //2 序列化反序列化
                ////既能通用，又能性能好
                //Func<People, PeopleCopy> func = p => new PeopleCopy()
                //{
                //    Id = p.Id,
                //    Name = p.Name,
                //    Age = p.Age
                //};
                //PeopleCopy peopleCopy3 = func.Invoke(people);
                ////想办法去动态拼装这个委托，然后缓存下委托，后面再次转换时就没有性能损耗了
                //PeopleCopy peopleCopy4 = ExpressionMapper.Trans<People, PeopleCopy>(people);
                //PeopleCopy peopleCopy5 = ExpressionMapper.Trans<People, PeopleCopy>(people);

                //PeopleCopy peopleCopy6 = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
                //PeopleCopy peopleCopy7 = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);

                {
                    People people = new People()
                    {
                        Id = 11,
                        Name = "Eleven",
                        Age = 31
                    };
                    long common = 0;
                    long generic = 0;
                    long cache = 0;
                    long reflection = 0;
                    long serialize = 0;
                    {
                        Stopwatch watch = new Stopwatch();
                        watch.Start();
                        for (int i = 0; i < 1_000_000; i++)
                        {
                            PeopleCopy peopleCopy = new PeopleCopy()
                            {
                                Id = people.Id,
                                Name = people.Name,
                                Age = people.Age
                            };
                        }
                        watch.Stop();
                        common = watch.ElapsedMilliseconds;
                    }
                    {
                        Stopwatch watch = new Stopwatch();
                        watch.Start();
                        for (int i = 0; i < 1_000_000; i++)
                        {
                            PeopleCopy peopleCopy = ReflectionMapper.Trans<People, PeopleCopy>(people);
                        }
                        watch.Stop();
                        reflection = watch.ElapsedMilliseconds;
                    }
                    {
                        Stopwatch watch = new Stopwatch();
                        watch.Start();
                        for (int i = 0; i < 1_000_000; i++)
                        {
                            PeopleCopy peopleCopy = SerializeMapper.Trans<People, PeopleCopy>(people);
                        }
                        watch.Stop();
                        serialize = watch.ElapsedMilliseconds;
                    }
                    {
                        Stopwatch watch = new Stopwatch();
                        watch.Start();
                        for (int i = 0; i < 1_000_000; i++)
                        {
                            PeopleCopy peopleCopy = ExpressionMapper.Trans<People, PeopleCopy>(people);
                        }
                        watch.Stop();
                        cache = watch.ElapsedMilliseconds;
                    }
                    {
                        Stopwatch watch = new Stopwatch();
                        watch.Start();
                        for (int i = 0; i < 1_000_000; i++)
                        {
                            PeopleCopy peopleCopy = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
                        }
                        watch.Stop();
                        generic = watch.ElapsedMilliseconds;
                    }

                    Console.WriteLine($"common = {common} ms");
                    Console.WriteLine($"reflection = {reflection} ms");
                    Console.WriteLine($"serialize = {serialize} ms");
                    Console.WriteLine($"cache = {cache} ms");
                    Console.WriteLine($"generic = {generic} ms");
                    //性能比automapper

                }
                //既需要动态，又需要保证性能（硬编码），--动态生成硬编码--表达式目录树拼装!!
            }
            #endregion
        }

        public Func<int, int, int> xxw()
        {
            return (m, n) => m * n + m + n + 2; ;
        }
    }
}
